package com.bl.student.api.filters;

import com.bl.student.common.ApiResponseBody;
import com.bl.student.common.ApiResponseCode;
import com.bl.student.common.utils.CommonUtils;
import com.bl.student.common.utils.JSONUtil;
import com.bl.student.dao.redis.UserInfoDao;
import com.bl.student.dao.redis.model.UserInfo;
import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.logging.log4j.core.config.Order;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

/**
 * Created by yujingyi on 2017/07/08.
 */
@Log4j2
@WebFilter(
        filterName = "authFilter",
        urlPatterns = "/student/apis/*",
        initParams = {
                @WebInitParam(name = "loginExcludePath", value = "/student/apis/login," +
                        "/student/apis/register," +
                        "/student/apis/file/upload," +
                        "/student/apis/task/get_task_list_multi," +
                        "/student/apis/apply/get_task_list," +
                        "/student/apis/task/get_task_detail," +
                        "/student/apis/task/get_task_list," +
                        "/student/apis/partya/register," +
                        "/student/apis/partya/login," +
                        "/student/apis/mini_wechat_login," +
                        "/student/apis/get_captcha," +
                        "/student/apis/ad," +
                        "/student/apis/notice/get," +
                        "/student/apis/reset"),
                @WebInitParam(name = "imperfectExcludePath", value = "/student/apis/tag/list," +
                        "/student/apis/school/list," +
                        "/student/apis/city/list," +
                        "/student/apis/user/my_info," +
                        "/student/apis/user/modify")
        })
@Order(3)
public class AuthFilter implements Filter {

    @Autowired
    UserInfoDao userInfoDao;

    private FilterConfig filterConfig;
    private List<String> loginExcludePath;
    private List<String> imperfectExcludePath;
    private List<String> teacherExcludePath;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        String loginExcludePaths = this.filterConfig.getInitParameter("loginExcludePath");
        if(!Strings.isNullOrEmpty(loginExcludePaths)){
            loginExcludePath = Splitter.on(',')
                    .omitEmptyStrings()
                    .trimResults()
                    .splitToList(loginExcludePaths);
        }
        String imperfectExcludePaths = this.filterConfig.getInitParameter("imperfectExcludePath");
        if(!Strings.isNullOrEmpty(imperfectExcludePaths)){
            imperfectExcludePath = Splitter.on(',')
                    .omitEmptyStrings()
                    .trimResults()
                    .splitToList(imperfectExcludePaths);
        }
        String teacherExcludePaths = this.filterConfig.getInitParameter("teacherExcludePath");
        if(!Strings.isNullOrEmpty(teacherExcludePaths)){
            teacherExcludePath = Splitter.on(',')
                    .omitEmptyStrings()
                    .trimResults()
                    .splitToList(teacherExcludePaths);
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)throws IOException, ServletException {

        // if need not filter
        if (!needFilter(request)) {
            filterChain.doFilter(request, response);
            return;
        }

        String token = getToken((HttpServletRequest) request);
        if (Strings.isNullOrEmpty(token)) {
            denyAccess(response);
            return;
        }
        Optional<UserInfo> userInfoOptional = userInfoDao.getUserInfo(token);

        if (userInfoOptional.isPresent()) {
            setUserInfo(request, userInfoOptional.get());
        } else {
            denyAccess(response);
            return;
        }

        filterChain.doFilter(request, response);
////        request.getServletContext()
//        if (!needFilter(request, loginExcludePath) || !needFilter(request, teacherExcludePath)) {
//            filterChain.doFilter(request, response);
//            return;
//        }
//
//        String token = request.getParameter(TOKEN_PARAM_NAME);
//        String mobile = request.getParameter(MOBILE_PARAM_NAME);
//        String sid = request.getParameter(SID_PARAM_NAME);
//        if (token == null || sid == null || mobile == null ||
//                StringUtils.isEmpty(mobile) || StringUtils.isEmpty(token) || StringUtils.isEmpty(sid)) {
//            denyAccess(response);
//            return;
//        }
//
//        Optional<UserInfo> userInfoOptional = userInfoDao.getUserInfo(mobile);
//        if (!userInfoOptional.isPresent()) {
//            denyAccess(response);
//            return;
//        }
//        UserInfo userInfo = userInfoOptional.get();
//
//        if ((token.equals(OMNIPOTENT_TOKEN) || token.equals(userInfo.getToken())
//                && (sid.equals(OMNIPOTENT_SID) || sid.equals(userInfo.getSId())))) {
//            // if imperfect
//            if (needFilter(request, imperfectExcludePath)) {
//                boolean perfect = Boolean.valueOf(userInfo.getPerfect());
//                if (!perfect) {
//                    denyAccess(response, ApiResponseCode.NOT_PERFECT);
//                    return;
//                }
//            }
//            setUserInfo(request, userInfo);
//        } else {
//            denyAccess(response);
//            return;
//        }
//
//        filterChain.doFilter(request, response);
    }

    private String getToken(HttpServletRequest httpServletRequest) {
        Optional<Cookie> cookieOptional = getCookie(httpServletRequest,"MOBILE");

        if (cookieOptional.isPresent()) {
            return cookieOptional.get().getValue();
        } else if (!Strings.isNullOrEmpty(httpServletRequest.getParameter(CommonUtils.TOKEN_PARAM))){
            return httpServletRequest.getParameter(CommonUtils.TOKEN_PARAM);
        } else {
            log.warn("no token is found, request: {}", httpServletRequest);
            return null;
        }
    }

    @Override
    public void destroy() {

    }

    private boolean needFilter(ServletRequest request) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        // get request url
        String reqUrl = httpServletRequest.getRequestURI().replace(
                httpServletRequest.getContextPath(), "");
        for(String path : loginExcludePath){
            if(reqUrl.equals(path)){
                return false;
            }
        }
        return true;
    }

    private void denyAccess(ServletResponse response) {
        denyAccess(response, ApiResponseCode.NOT_AUTHORIZED);
    }

    private void denyAccess(ServletResponse response, ApiResponseCode apiResponseCode) {
        try {
            PrintWriter outWriter = response.getWriter();
            outWriter.print(
                    JSONUtil.jsonEncode(
                            ApiResponseBody.createErrorBody(apiResponseCode.getCode(),
                                    apiResponseCode.getMsg())));
        } catch (IOException e) {
            log.error(ExceptionUtils.getRootCauseMessage(e));
        }
    }

    private Optional<Cookie> getCookie(HttpServletRequest httpServletRequest, String cookieName) {

        final Cookie[] cookies = httpServletRequest.getCookies();
        if (cookies != null && cookies.length > 0){
            for (Cookie cookie : cookies){
                if (cookieName.equals(cookie.getName())){
                    return Optional.fromNullable(cookie);
                }
            }
        }
        return Optional.absent();
    }

    private void setUserInfo(ServletRequest request, UserInfo userInfo) {
        request.setAttribute(CommonUtils.CURRENT_USER_INFO, userInfo);
    }


}
